package metric

import (
	"aicloud/monitor-apiserver/pkg/util"
	"aicloud/monitor-apiserver/server/response"
	"context"
	"fmt"
	v1 "github.com/prometheus/client_golang/api/prometheus/v1"
	"github.com/prometheus/common/model"
	"time"
)

type TrendRequest struct {
	Start    time.Time     `json:"start"`
	End      time.Time     `json:"end"`
	Interval time.Duration `json:"interval"`
}

type SeriesRequest struct {
	Label   string
	Samples []model.SamplePair
}

func BuildTrendRequest(start, end, interval string) (*TrendRequest, error) {
	var (
		duration time.Duration
	)
	startTime, err := util.ParseTime(start)
	if err != nil {
		return nil, err
	}
	endTime, err := util.ParseTime(end)
	if err != nil {
		return nil, err
	}
	value := interval[:len(interval)-1]
	unit := interval[len(interval)-1:]
	num, err := time.ParseDuration(value + "s")
	if err != nil {
		return nil, fmt.Errorf("invalid value in interval")
	}
	switch unit {
	case "s":
		duration = num
	case "m":
		duration = num * time.Minute
	case "h":
		duration = num * time.Hour
	case "d":
		duration = num * 24 * time.Hour
	case "w":
		duration = num * 7 * 24 * time.Hour
	case "M":
		duration = num * 30 * 24 * time.Hour
	case "Y":
		duration = num * 365 * 24 * time.Hour
	default:
		return nil, fmt.Errorf("unsupported unit in interval")
	}
	return &TrendRequest{
		Start:    startTime,
		End:      endTime,
		Interval: duration,
	}, nil
}

func Query(query string) ([]*model.Sample, error) {
	result, warnings, err := PromApiClient.Query(context.Background(), query, time.Now())
	if err != nil {
		return nil, fmt.Errorf("querying Prometheus: %v", err)
	}
	for _, warning := range warnings {
		util.GetLogger().Warnf("Warning: %s", warning)
	}
	vector, ok := result.(model.Vector)
	if !ok {
		return nil, fmt.Errorf("unexpected result type: %T", result)
	}
	if len(vector) == 0 {
		return nil, fmt.Errorf("empty result")
	}

	return vector, nil
}

func QueryRange(query string, req TrendRequest) ([]*model.SampleStream, error) {
	result, warnings, err := PromApiClient.QueryRange(context.Background(), query, v1.Range{
		Start: req.Start,
		End:   req.End,
		Step:  req.Interval,
	})
	if err != nil {
		return nil, fmt.Errorf("querying Prometheus: %v", err)
	}
	for _, warning := range warnings {
		util.GetLogger().Warningf("%s", warning)
	}
	switch result.Type() {
	case model.ValMatrix:
		matrix := result.(model.Matrix)
		if len(matrix) == 0 {
			return nil, fmt.Errorf("empty result")
		}
		return matrix, nil
	default:
		return nil, fmt.Errorf("unexpected result type: %s", result.Type())
	}
}

func ConvertSamplePair(pairs []model.SamplePair) []response.ResultEntry {
	entries := make([]response.ResultEntry, len(pairs))
	for _, samplePair := range pairs {
		entries = append(entries, response.ResultEntry{
			Timestamp: time.Unix(int64(samplePair.Timestamp), 0),
			Value:     float64(samplePair.Value),
		})
	}
	return entries
}

func GetSeries(seriesGroup []SeriesRequest) []response.Series {
	group := make([]response.Series, 0)
	for _, seriesRequest := range seriesGroup {
		group = append(group, response.Series{
			Label: seriesRequest.Label,
			Data:  ConvertSamplePair(seriesRequest.Samples),
		})
	}
	return group
}
